#include "particles.h"
#include "common.h"
#include <fstream>

/*==============================================================================
						Classes of effect types
==============================================================================*/

ParticleEffect::ParticleEffect(Video* video, Sound* sound, const std::string &filename)
	: Effect(video, sound), data_filename(filename), particles(NULL), last_update_time(0.0f)
{
	LOG_INFO("Initilizing particles system...");

	// Introduce default values for variables
	emission_rate = 0.0f;
	start_pos = NULL_VECTOR2;
	speed_min = NULL_VECTOR2;
	speed_max = NULL_VECTOR2;
	size_min = 0.0f;
	size_max = 0.0f;

	max_particles = 0;
	particles_count = 0;
	last_particle_born = 0.0f;
	particle_lifetime = 0.0f;

	ReadData();
	TestData();

	if (max_particles != 0)
	{
		particles = new Particle[max_particles];
		if (particles != NULL)
			LOG_INFO("Particles memory allocated successfully.");
		else LOG_ERROR("Particles memory allocated unsuccessfully");
	}
}

ParticleEffect::~ParticleEffect()
{
	LOG_INFO("Closing particles system...");

	delete[] particles;
}

// Draw all particles on screen
void ParticleEffect::Render()
{
	video->DrawBackground(COLOR_BLACK);

	// Just draw particles on screen. Could add background.
	for (int i=0; i<particles_count; i++)
	{
		DrawParticle(i);
	}
}

// Draw a particle from array
void ParticleEffect::DrawParticle(int id)
{
	Vector2 tl, br;
	Color color = particles[id].color;

	tl.x = particles[id].pos.x;
	tl.y = particles[id].pos.y;
	br.x = particles[id].size;
	br.y = particles[id].size;

	video->DrawRectangle(tl, br, color);
}

// Update particles: creates, kills, updates position
void ParticleEffect::Update()
{
	SystemUpdate();

	if (last_update_time == 0.0f)
	{
		dt = 0.0f;
		last_update_time = GetTime();
		return;
	}

	dt = GetTime() - last_update_time;
	last_update_time = GetTime();

	// Update all particles
	for (int i=0; i<particles_count; ++i)
	{
		// Kills particle, if the time has come
		if (GetTime() >= particles[i].death_time)
		{
			KillParticle(i);
			i--;
			continue;
		}

		UpdatePos(i);
	}

	// Create, if it is time to born
	if (GetTime() - last_particle_born > (1 / emission_rate))
	{
		if (particles_count < max_particles)
		{
			ColorHSV col = ToHSV(Color(255,255,0,255));

			// Creates yellow particle at given position
			CreateParticle(GetTime(), start_pos, Vector2(0.07f, 0.1f), col, 0.0019f);
			last_particle_born = GetTime();
		}
	}
}

// Read from data file
void ParticleEffect::ReadData()
{
	std::string name = "";
//	effects_count = 0;

	// read from file
	std::ifstream fin(data_filename.c_str());
	if (!fin)
	{
		LOG_ERROR("Failed to open data file.");
		return;
	}

	//fin >> name;
//	if (name == "EFFECTS_COUNT") fin >> name;//fin >> effects_count;

	//for (int i=0; i<=effects_count; ++i)
	//{
		// Errors if bad data
		//birth_time = 0.0f;
		//death_time = 0.0f;

		while (!fin.eof() || name != "EFFECT_END" || name != "EXAMPLE_END")
		{
			fin >> name;

			if (name == "EMISSION_RATE") fin >> emission_rate;
			if (name == "START_POSITION") fin >> start_pos.x >> start_pos.y;
			if (name == "MAX_PARTICLES") fin >> max_particles;
			if (name == "PARTICLE_LIFETIME") fin >> particle_lifetime;
			if (name == "PARTICLE_SIZE_MIN") fin >> size_min;
			if (name == "PARTICLE_SIZE_MAX") fin >> size_max;
			if (name == "PARTICLE_SPEED_MIN") fin >> speed_min.x >> speed_min.y;
			if (name == "PARTICLE_SPEED_MAX") fin >> speed_max.x >> speed_max.y;
			if (name == "EFFECT_END" || name == "EXAMPLE_END") break;
			//else break;

		}

	//	if (name == "EFFECT_END") effects.push_back(new_effect);
		
	//	if (new_effect.max_particles > max_particles)
	//		max_particles = new_effect.max_particles;
	//}
	fin.close();
}

// Write data to a file to check if everything was read correctly
void ParticleEffect::TestData()
{
	std::ofstream fout("test.txt");

	//fout << "EFFECTS_COUNT " << effects_count << "\n\n";
	
//	for (int i=0; i<effects_count; i++)
//	{
		//fout << "PARTICLES_BIRTH_TIME " << birth_time << '\n';
		fout << "EMISSION_RATE " << emission_rate << '\n';
		fout << "START_POSITION " << start_pos.x << ' ' << start_pos.y << '\n';
		fout << "MAX_PARTICLES " << max_particles << '\n';
		fout << "PARTICLE_LIFETIME " << particle_lifetime << '\n';
		fout << "PARTICLE_SIZE_MIN " << size_min << '\n';
		fout << "PARTICLE_SIZE_MAX " << size_max << '\n';
		fout << "PARTICLE_SPEED_MIN " << speed_min.x << ' ' << speed_min.y << '\n';
		fout << "PARTICLE_SPEED_MAX " << speed_max.x << ' ' << speed_max.y << '\n';
		fout << "EFFECT_END" << "\n\n";
//	}

	fout.close();
}

// Adds new member to particles array
void ParticleEffect::CreateParticle(float birth_time, Vector2 pos, Vector2 speed, ColorHSV col, float size)
{
	Particle p;
	p.birth_time = birth_time;
	p.death_time = p.birth_time + particle_lifetime;
	p.pos = pos;
	p.speed = speed;
	p.color = ToRGB(col); // take color depending on sound_hz
	p.size = size;

	if (particles_count >= max_particles) return;
	particles[particles_count] = p;
	particles_count++;
}

// Deletes a particle from array
void ParticleEffect::KillParticle(int id)
{
	// Just copy last particle to i-th's place
	particles[id] = particles[particles_count-1];
	particles_count--;
}

// Get number of maximum allowed particles at one time
int ParticleEffect::GetMaxParticles()
{
	return max_particles;
}

// Get current number of particles
int ParticleEffect::GetParticlesCount()
{
	return particles_count;
}
